package com.common.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpUtils;


import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;


public class HttpClientUtil {
	
	private static final int connectTimeout = 5000;
    private static final int requestTimeout = 30 * 1000;
    private static final int tryTimes = 1;
    private int times = 0;

    private static PoolingClientConnectionManager cm = null;
    private static HttpParams params = new BasicHttpParams();
    private static Map<String, String> commHeader;

    private HttpClient getHttpClient() {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                        throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                        throws CertificateException {
                }
            };
            ctx.init(null, new TrustManager[]{tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            HttpConnectionParams.setConnectionTimeout(params, 300000);
            HttpConnectionParams.setSoTimeout(params, 1800000);
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
            schemeRegistry.register(new Scheme("https", 443, ssf));
            cm = new PoolingClientConnectionManager(schemeRegistry);
            cm.setMaxTotal(200);
            cm.setDefaultMaxPerRoute(20);
        } catch (Exception e) {
            e.printStackTrace();
        }
        HttpClient httpclient = new DefaultHttpClient(cm, params);
        return httpclient;
    }

    private HttpObject get(String url, Map<String, String> header, String toCode) {
        HttpObject result = new HttpObject();
        byte[] data = null;
        HttpClient httpclient = getHttpClient();
        try {
            HttpGet httpget = new HttpGet(url);
            if ((header == null) || (header.size() == 0)) {
                header = commHeader;
            } else {
                Iterator iter = header.entrySet().iterator();
                while (iter.hasNext()) {
                    Entry entry = (Entry) iter.next();
                    String key = (String) entry.getKey();
                    String val = (String) entry.getValue();
                    httpget.setHeader(key, val);
                }
            }
            HttpResponse response = null;
            response = httpclient.execute(httpget);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                int code = response.getStatusLine().getStatusCode();
                result.setCode(code);
                Header contentType = httpEntity.getContentType();
                if (contentType != null) {
                    String encode = null;
                    encode = contentType.getValue();
                    String key = "charset=";
                    int len = key.length();
                    if (encode.contains("charset="))
                        encode = encode.substring(encode.indexOf(key) + len);
                    else {
                        encode = null;
                    }
                    if (encode != null) {
                        toCode = encode;
                    }
                }
                result.setCharSet(toCode);
                data = EntityUtils.toByteArray(httpEntity);
                httpEntity.consumeContent();
                result.setData(data);
                Header[] head = response.getAllHeaders();
                for (Header h : head) {
                    result.getHeader().put(h.getName(), h.getValue());
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            httpclient.getConnectionManager().shutdown();
        }
        return result;
    }

    HttpObject getHttpObject(String url, Map<String, String> header, String toCode) {
        HttpObject res = get(url, header, toCode);
        while ((this.times < tryTimes) && (res.getCode() > 300)) {
            res = get(url, header, toCode);
            this.times += 1;
        }
        return res;
    }

    public static HttpObject getObject(String url, Map<String, String> header, String encode) {
    	HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, header, encode);
        return res;
    }

    public static HttpObject getObject(String url, Map<String, String> header) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, header, null);
        return res;
    }

    public static HttpObject getObject(String url, String encode) {
    	HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, null, encode);
        return res;
    }

    public static HttpObject getObject(String url) {
    	HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, null, null);
        return res;
    }

    public static String getString(String url, Map<String, String> header, String encode) {
    	HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, header, encode);
        return res.getHtml();
    }

    public static String getString(String url, Map<String, String> header) {
    	HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, header, null);
        return res.getHtml();
    }

    public static String getString(String url, String encode) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, null, encode);
        return res.getHtml();
    }

    public static String getString(String url) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, null, null);
        return res.getHtml();
    }

    public static byte[] getByte(String url, Map<String, String> header, String encode) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, header, encode);
        return res.getData();
    }

    public static byte[] getByte(String url, Map<String, String> header) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, header, null);
        return res.getData();
    }

    public static byte[] getByte(String url, String encode) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, null, encode);
        return res.getData();
    }

    public static byte[] getByte(String url) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, null, null);
        return res.getData();
    }

    private HttpObject post(String url, Map<String, Object> body, Map<String, String> header, String encode) {
        HttpObject result = new HttpObject();
        byte[] data = null;
        HttpResponse response = null;
        HttpClient httpclient = getHttpClient();
        HttpParams params = httpclient.getParams();
        HttpConnectionParams.setConnectionTimeout(params, 300000);
        HttpConnectionParams.setSoTimeout(params, 1800000);
        List nvps = new ArrayList();
        Iterator<Entry<String, Object>> it = body.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, Object> entry = (Entry) it.next();
            String key = StringUtils.defaultString(entry.getKey());
            Object val = entry.getValue();
            if (StringUtils.isNotBlank(key) && val != null) {
                if (val.getClass().isArray()) {
                    Object[] values = (Object[]) val;
                    for (Object o : values) {
                        String value = String.valueOf(o);
                        NameValuePair nvp = new BasicNameValuePair(key, value);
                        nvps.add(nvp);
                    }
                } else {
                    String value = String.valueOf(val);
                    NameValuePair nvp = new BasicNameValuePair(key, value);
                    nvps.add(nvp);
                }
            }
        }
        HttpPost httppost = new HttpPost(url);
        if ((header == null) || (header.size() == 0)) {
            header = commHeader;
        } else {
            Iterator iter = header.entrySet().iterator();
            while (iter.hasNext()) {
                Entry entry = (Entry) iter.next();
                String key = (String) entry.getKey();
                String val = (String) entry.getValue();
                httppost.setHeader(key, val);
            }
        }
        try {
            httppost.setEntity(new UrlEncodedFormEntity(nvps, encode));
            response = httpclient.execute(httppost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                int code = response.getStatusLine().getStatusCode();
                result.setCode(code);
                Header contentType = httpEntity.getContentType();
                if (contentType != null) {
                    String _encode = null;
                    _encode = contentType.getValue();
                    String key = "charset=";
                    int len = key.length();
                    if (_encode.contains("charset="))
                        _encode = _encode.substring(_encode.indexOf(key) + len);
                    else {
                        _encode = null;
                    }
                    if (_encode != null) {
                        encode = _encode;
                    }
                }
                result.setCharSet(encode);
                data = EntityUtils.toByteArray(httpEntity);
                httpEntity.consumeContent();
                result.setData(data);
                Header[] head = response.getAllHeaders();
                for (Header h : head) {
                    result.getHeader().put(h.getName(), h.getValue());
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return result;
    }

    private HttpObject postObject(String url, Map<String, Object> map, Map<String, String> header, String encode) {
        HttpObject res = post(url, map, header, encode);
        while ((this.times < tryTimes) && (res.getCode() > 300)) {
            res = post(url, map, header, encode);
            this.times += 1;
        }
        return res;
    }

    public static HttpObject postString(String url, Map<String, Object> map, Map<String, String> header, String encode) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, map, header, encode);
        return res;
    }

    public static HttpObject postString(String url, Map<String, Object> map, Map<String, String> header) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, map, header, "utf-8");
        return res;
    }

    public static String postString(String url, Map<String, Object> map) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, map, null, "utf-8");
        return res.getHtml();
    }

    public static byte[] postByte(String url, Map<String, Object> map, Map<String, String> header, String encode) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, map, header, encode);
        return res.getData();
    }

    public static byte[] postByte(String url, Map<String, Object> map, Map<String, String> header) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, map, header, "utf-8");
        return res.getData();
    }

    public static byte[] postByte(String url, Map<String, Object> map) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, map, null, "utf-8");
        return res.getData();
    }


    //------------------------------------------------------------------------------------------------------------------

    private HttpObject post(String url, String query, Map<String, String> header, String encode) {
        HttpObject result = new HttpObject();
        byte[] data = null;
        HttpResponse response = null;
        HttpClient httpclient = getHttpClient();
        HttpParams params = httpclient.getParams();
        HttpConnectionParams.setConnectionTimeout(params, 300000);
        HttpConnectionParams.setSoTimeout(params, 1800000);
        HttpPost httppost = new HttpPost(url);
        if ((header == null) || (header.size() == 0)) {
            header = commHeader;
        } else {
            Iterator iter = header.entrySet().iterator();
            while (iter.hasNext()) {
                Entry entry = (Entry) iter.next();
                String key = (String) entry.getKey();
                String val = (String) entry.getValue();
                httppost.setHeader(key, val);
            }
        }
        try {

            StringEntity entity = new StringEntity(StringUtils.defaultString(query));
            entity.setContentEncoding("utf-8");
            httppost.setEntity(entity);
            response = httpclient.execute(httppost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                int code = response.getStatusLine().getStatusCode();
                result.setCode(code);
                Header contentType = httpEntity.getContentType();
                if (contentType != null) {
                    String _encode = null;
                    _encode = contentType.getValue();
                    String key = "charset=";
                    int len = key.length();
                    if (_encode.contains("charset="))
                        _encode = _encode.substring(_encode.indexOf(key) + len);
                    else {
                        _encode = null;
                    }
                    if (_encode != null) {
                        encode = _encode;
                    }
                }
                result.setCharSet(encode);
                data = EntityUtils.toByteArray(httpEntity);
                httpEntity.consumeContent();
                result.setData(data);
                Header[] head = response.getAllHeaders();
                for (Header h : head) {
                    result.getHeader().put(h.getName(), h.getValue());
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return result;
    }

    private HttpObject postObject(String url, String query, Map<String, String> header, String encode) {
        HttpObject res = post(url, query, header, encode);
        while ((this.times < tryTimes) && (res.getCode() > 300)) {
            res = post(url, query, header, encode);
            this.times += 1;
        }
        return res;
    }

    public static HttpObject postString(String url, String query, Map<String, String> header, String encode) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, query, header, encode);
        return res;
    }

    public static HttpObject postString(String url, String query, Map<String, String> header) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, query, header, "utf-8");
        return res;
    }

    public static String postString(String url, String query) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, query, null, "utf-8");
        return res.getHtml();
    }

    private HttpObject post(String url, byte[] postData, Map<String, String> header, String encode) {
        HttpObject result = new HttpObject();
        byte[] data = null;
        HttpResponse response = null;
        HttpClient httpclient = new DefaultHttpClient();
        HttpParams params = httpclient.getParams();
        HttpConnectionParams.setConnectionTimeout(params, 300000);
        HttpConnectionParams.setSoTimeout(params, 1800000);
        HttpPost httppost = new HttpPost(url);
        if ((header == null) || (header.size() == 0)) {
            header = commHeader;
        } else {
            Iterator iter = header.entrySet().iterator();
            while (iter.hasNext()) {
                Entry entry = (Entry) iter.next();
                String key = (String) entry.getKey();
                String val = (String) entry.getValue();
                httppost.setHeader(key, val);
            }
        }
        try {
            httppost.setEntity(new ByteArrayEntity(postData));
            response = httpclient.execute(httppost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                int code = response.getStatusLine().getStatusCode();
                result.setCode(code);
                Header contentType = httpEntity.getContentType();
                if (contentType != null) {
                    String _encode = null;
                    _encode = contentType.getValue();
                    String key = "charset=";
                    int len = key.length();
                    if (_encode.contains("charset="))
                        _encode = _encode.substring(_encode.indexOf(key) + len);
                    else {
                        _encode = null;
                    }
                    if (_encode != null) {
                        encode = _encode;
                    }
                }
                result.setCharSet(encode);
                data = EntityUtils.toByteArray(httpEntity);
                httpEntity.consumeContent();
                result.setData(data);
                Header[] head = response.getAllHeaders();
                for (Header h : head) {
                    result.getHeader().put(h.getName(), h.getValue());
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return result;
    }

    private HttpObject postObject(String url, byte[] data, Map<String, String> header, String encode) {
        HttpObject res = post(url, data, header, encode);
        while ((this.times < tryTimes) && (res.getCode() > 300)) {
            res = post(url, data, header, encode);
            this.times += 1;
        }
        return res;
    }

    public static byte[] postByte(String url, byte[] data, Map<String, String> header, String encode) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, data, header, encode);
        return res.getData();
    }

    public static byte[] postByte(String url, byte[] data, Map<String, String> header) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, data, header, "utf-8");
        return res.getData();
    }

    public static byte[] postByte(String url, byte[] data) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.postObject(url, data, null, "utf-8");
        return res.getData();
    }

    public static String getUrl(String url, String toCode) {
        HttpClientUtil client = new HttpClientUtil();
        HttpObject res = client.getHttpObject(url, null, toCode);
        if (res.getHeader().containsKey("Location")) {
            url = (String) res.getHeader().get("Location");
            getUrl(url, toCode);
        }
        return url;
    }

    static {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                        throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                        throws CertificateException {
                }
            };
            ctx.init(null, new TrustManager[]{tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            HttpConnectionParams.setConnectionTimeout(params, 300000);
            HttpConnectionParams.setSoTimeout(params, 1800000);
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
            schemeRegistry.register(new Scheme("https", 443, ssf));
            cm = new PoolingClientConnectionManager(schemeRegistry);
            cm.setMaxTotal(200);
            cm.setDefaultMaxPerRoute(20);
        } catch (Exception e) {
            e.printStackTrace();
        }

        commHeader = null;
        commHeader = new HashMap();
        commHeader.put("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 ( .NET CLR 3.5.30729)");
        commHeader.put("Accept-Encoding", "Accept-Encoding");
        commHeader.put("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
        commHeader.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        commHeader.put("Connection", "close");
        commHeader.put("Accept-Encoding", "gzip, deflate");
        commHeader.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    }


}
